/*
THIS FILE IS PART OF THE >>ADRENALIN-3D-GRAFIC-ENGINE<<
for latest info visit http://www.creative-games.de

Copyright (c) 2008-2009 by Marco Schneider

This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License (LGPL) as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.

*/

#ifndef __ADL_MATH_VECTOR4_H__
#define __ADL_MATH_VECTOR4_H__

#include "../Defines.h"

// Diese Klasse wird aus Adrenalin.dll exportiert.
namespace Adrenalin
{
	namespace Math
	{
		enum ADRENALIN_API EPlaneSide
		{
			NEGATIVE,
			POSITIVE,
			NONE,
		};

		template<typename T=float>
		struct ADRENALIN_API Vector4
		{
			union
			{
				struct	{
					T x, y, z, w;
				};
				struct	{
					T r, g, b, a;
				};
				T v[4];
			};

			#pragma region Constructors
			Vector4() {}
			Vector4( T fX, T fY, T fZ, T fW ) : x(fX), y(fY), z(fZ), w(fW) {}
			Vector4( T f[4] ) : x(f[0]), y(f[1]), z(f[2]), w(f[3]) {}
			#pragma endregion 

			#pragma region Operators
			operator T*	()	{	return v;	}
			operator const T*	()	const	{	return v;	}

			Vector4& operator = ( const T& inX )	{ x=y=z=w=inX;	return *this; }
			Vector4& operator += ( const Vector4& inVec )	{ x += inVec.x; y += inVec.y; z += inVec.z;	w += inVec.w; return *this; }
			Vector4& operator -= ( const Vector4& inVec )	{ x -= inVec.x; y -= inVec.y; z -= inVec.z; w -= inVec.w; return *this; }
			Vector4& operator *= ( const Vector4& inVec )	{ x *= inVec.x; y *= inVec.y; z *= inVec.z; w *= inVec.w; return *this; }
			Vector4& operator /= ( const Vector4& inVec )	{ x /= inVec.x, y /= inVec.y; z /= inVec.z; w /= inVec.w; return *this; }

			Vector4& operator + ( const Vector4& inVec ) const	{ return Vector4( x + inVec.x, y + inVec.y, z + inVec.z, w + inVec.w ); }
			Vector4& operator - ( const Vector4& inVec ) const	{ return Vector4( x - inVec.x, y - inVec.y, z - inVec.z, w - inVec.w ); }
			Vector4& operator * ( const Vector4& inVec ) const	{ return Vector4( x * inVec.x, y * inVec.y, z * inVec.z, w * inVec.w ); }
			Vector4& operator * ( const T& scalar )	const { return Vector4( x * scalar, y * scalar, z * scalar, w * scalar );	}
			Vector4& operator / ( const Vector4& inVec ) const	{ return Vector4( x / inVec.x, y / inVec.y, z / inVec.z, w / inVec.w ); }
			Vector4& operator / ( const T& scalar )	const {	return Vector4( x / scalar, y / scalar, z / scalar, w / scalar ); }

			Vector4& operator - () { return Vector4( -x,-y,-z,-w ); }
			#pragma endregion 

			#pragma region Methodes
			Vector4& Normalize( void )
			{
				T tLength = GetLength();
				if(tLength==0)
					return *this;

				tLength = 1.0f / tLength;
				x *= tLength;
				y *= tLength;
				z *= tLength;
				w *= tLength;
				return *this;
			}
			T GetLength( void )	{ return sqrt(x*x + y*y + z*z + w*w); }
			T DotProduct( const Vector4& inVec ) const {	return x*inVec.x + y*inVec.y + z*inVec.z + w*inVec.w;	}
			T DotProduct( const Vector3<float>& inVec ) const { return x*inVec.x + y*inVec.y + z*inVec.z + w; }
			EPlaneSide GetSide( const Vector3<float>& inVec ) const 
			{
				float fDistance = this->DotProduct( inVec );

				if( fDistance < 0.0 )
					return NEGATIVE;
			
				if( fDistance > 0.0 )
					return POSITIVE;

				return NONE;
			}
			bool IsNull( void )
			{
				if( (x == 0) && (y == 0) && (z == 0) && (w == 0) ) {
					return true;
				} else {
					return false;
				}
			}
			#pragma endregion
		};
	}//namespace Math
}//namespace Adrenalin

#endif